import Foundation

protocol DWJsonDictValue {
    static func dw_subType() -> Any.Type
}

extension NSDictionary: DWJsonDictValue {
    
    static func dw_subType() -> Any.Type {
        if let optionType = self.Value as? DWJsonOptionalValue.Type {
            return optionType.dw_subType()
        }
        return self.Value
    }
    
}
extension Dictionary: DWJsonDictValue {
    
    static func dw_subType() -> Any.Type {
        if let optionType = self.Value as? DWJsonOptionalValue.Type {
            return optionType.dw_subType()
        }
        return self.Value
    }
    
}

func dw_dict_value(_ value: Any, type: Any.Type?) -> [String : Any]? {
    guard let json = dw_valueToDic(value) else { return nil }
    if let subType = type as? DWJsonConvert.Type {
        return json.compactMapValues {
            if let dict = dw_valueToDic($0) {
                return subType.dw_model(dict)
            }
            return nil
        }
    }
    if let subType = type as? DWJsonArrayValue.Type {
        let arraySubType = subType.dw_subType()
        return json.compactMapValues {
            return dw_array($0, type: Array<Any>.self, subType: arraySubType)
        }
    }
    if let subType = type as? (any RawRepresentable.Type) {
        return json.compactMapValues {
            return subType.dw_enum($0)
        }
    }
    if let subType = type as? DWJsonDictValue.Type {
        return json.compactMapValues {
            return dw_dict_value($0, type: subType)
        }
    }
    return json.compactMapValues {
        return dw_model_normal_value($0, type:type)
    }
}

func dw_dict(_ value: Any, type: Any.Type, subType : Any.Type?) -> DWJsonDictValue? {
    guard let dict = dw_dict_value(value, type: subType) else { return nil }
    return type is NSMutableDictionary.Type ? NSMutableDictionary.init(dictionary: dict) : dict
}
